package com.seeqool.v1;

import java.util.Vector;

import com.seeqool.v1.chartframes.Bar100ChartFrame;
import com.seeqool.v1.chartframes.BarChartFrame;
import com.seeqool.v1.chartframes.CategoryHistogramFrame;
import com.seeqool.v1.chartframes.PieChartFrame;
import com.seeqool.v1.chartframes.XYScatterFrame;
import com.seeqool.v1.datamodel.SQLTable;

class ChartInfo extends Object {}

class HistogramInfo extends ChartInfo {
	public int majorAxis;
	public HistogramInfo(int colIndex) { majorAxis = colIndex; }
}

class PieOrBarInfo extends ChartInfo {
	public int majorAxis;
	public Vector<Integer> minorAxes=new Vector<Integer>();
	public PieOrBarInfo(ChartInfo protoType, int colIndex) {
		majorAxis=((HistogramInfo) protoType).majorAxis;
		minorAxes.add(colIndex);
	}
	public void addColumn(int colIndex) { minorAxes.add(colIndex); }
}

class XYScatterInfo extends ChartInfo {
	public int majorAxis;
	public Vector<Integer> minorAxes;
	public Vector<Integer> dotLabels;
	public XYScatterInfo(ChartInfo protoType, int colIndex) {
		if (protoType instanceof HistogramInfo) {
			majorAxis=((HistogramInfo) protoType).majorAxis;
			minorAxes=new Vector<Integer>();
			dotLabels=new Vector<Integer>();
			minorAxes.add(colIndex);
		} else {
			majorAxis=((XYScatterInfo) protoType).majorAxis;
			minorAxes=((XYScatterInfo) protoType).minorAxes;
			dotLabels=((XYScatterInfo) protoType).dotLabels;
		}
	}
	public void addColumn(int colIndex) { minorAxes.add(colIndex); }
	public void addLabels(int colIndex) { dotLabels.add(colIndex); }
}

class XYBubbleInfo extends XYScatterInfo {
	public Vector<Integer> sizeAxes=new Vector<Integer>();
	public XYBubbleInfo(ChartInfo protoType, int colIndex) {
		super(protoType, colIndex);
		sizeAxes.add(colIndex);
	}
	public void addSize(int colIndex) { sizeAxes.add(colIndex); }
}

public class ChartDispatcher {
	
	enum ParseState                {IDLE, HIST_C, HIST_X, PIE,   BAR,   XY,      SCATTER, BUBBLE, BUBB};
	static String[] stateChoices = {"CX", "CXSY", "CXY",  "CXS", "CXY", "CXYSL", "CXYL",  "CXYL", "SL"};

	public static void show(ResultPanel resultFrame, SQLTable queryResult) {
		ChartInfo currentChart=null;
		Vector<Integer> dataGroups = new Vector<Integer>();
		ParseState state=ParseState.IDLE;
		for (int a=0;a<queryResult.getColumnCount();a++) {
			char colType = queryResult.getColID(a);
			if (colType=='G') {
				dataGroups.add(a);
			} else {
				if (stateChoices[state.ordinal()].contains(((Character) colType).toString())) {
					switch (colType) {
						case 'C':
						case 'X':
							if (currentChart!=null) buildChart(resultFrame, state, currentChart, queryResult);
							if (colType=='C') state=ParseState.HIST_C; else state=ParseState.HIST_X;
							currentChart=new HistogramInfo(a);
							break;
						case 'L':
							((XYScatterInfo) currentChart).addLabels(a);
							break;
						default:	
							switch (state) {
								case HIST_C:
									currentChart=new PieOrBarInfo(currentChart, a);
									if (colType=='S') state=ParseState.PIE; else state=ParseState.BAR;
									break;
								case HIST_X:
									currentChart=new XYScatterInfo(currentChart, a);
									state=ParseState.XY;
									break;
								case PIE:
								case BAR:
									((PieOrBarInfo) currentChart).addColumn(a);
									break;
								case XY:
									if (colType=='Y') {
										((XYScatterInfo) currentChart).addColumn(a);
										state=ParseState.SCATTER;
									} else {
										currentChart = new XYBubbleInfo(currentChart, a);
										state=ParseState.BUBBLE;
									}
									break;
								case SCATTER:
									((XYScatterInfo) currentChart).addColumn(a);
									break;
								case BUBBLE:
									((XYBubbleInfo) currentChart).addColumn(a);
									state=ParseState.BUBB;
									break;
								case BUBB:
									((XYBubbleInfo) currentChart).addSize(a);
									state=ParseState.BUBBLE;
									break;										
							}
					
					}
				} else {
					System.out.println("Found "+colType+" but expected "+stateChoices[state.ordinal()]);
				}
			}
		}
		if (currentChart!=null) buildChart(resultFrame, state, currentChart, queryResult);
		resultFrame.arrangeCharts();
	}
	
	static void buildChart(ResultPanel resultFrame, ParseState state, ChartInfo chart, SQLTable queryResult) {
		HistogramInfo hgi;
		PieOrBarInfo pobi;
		XYScatterInfo xysi;
		Integer[] minorAxes;
		switch (state) {
			case BUBB:
				System.out.println("Incomplete Bubble Chart!");
				break;
			case PIE:
				pobi = (PieOrBarInfo) chart;
				if (pobi.minorAxes.size()==1) {
					resultFrame.addChart(new PieChartFrame(queryResult, pobi.majorAxis, pobi.minorAxes.get(0)));
				} else {
					minorAxes = new Integer[pobi.minorAxes.size()];
					pobi.minorAxes.copyInto(minorAxes);
					resultFrame.addChart(new Bar100ChartFrame(queryResult, pobi.majorAxis, minorAxes));
				}
				break;
			case BAR:
				pobi = (PieOrBarInfo) chart;
				minorAxes = new Integer[pobi.minorAxes.size()];
				pobi.minorAxes.copyInto(minorAxes);
				resultFrame.addChart(new BarChartFrame(queryResult, pobi.majorAxis, minorAxes));
				break;
			case HIST_C:
				hgi = (HistogramInfo) chart;
				resultFrame.addChart(new CategoryHistogramFrame(queryResult, hgi.majorAxis));
				break;
			case XY:
			case SCATTER:
				xysi = (XYScatterInfo) chart;
				minorAxes = new Integer[xysi.minorAxes.size()];
				xysi.minorAxes.copyInto(minorAxes);
				resultFrame.addChart(new XYScatterFrame(queryResult, xysi.majorAxis, minorAxes));
				break;
		}
	}
}
